package internal

import (
	"context"
	"errors"
	"github.com/samber/lo"
	"gorm.io/gorm"
	"k9-panel/app/model"
	"k9-panel/app/permission"
	"k9-panel/app/query"
	errors2 "k9-panel/app/service/contract/errors"
	"k9-panel/app/service/dto"
	"k9-panel/pkg/gslice"
)

type ProjectService struct {
}

func (receiver *ProjectService) Update(obj *model.Project) (id uint, err error) {
	if obj == nil || obj.ID == 0 {
		return 0, errors.New("没有指定项目！")
	}
	first, err := query.Project.Where(query.Project.ID.Eq(obj.ID)).First()
	if err != nil {
		return 0, err
	}
	config, err := query.HistoryConfig.Where(query.HistoryConfig.ProjectId.Eq(int(first.ID))).First()
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return 0, err
	}
	if config != nil && obj.Name != first.Name {
		return 0, errors.New("存在已发布配置，不允许修改项目名称！")
	}
	updates, err := query.Project.Where(query.Project.ID.Eq(obj.ID)).Updates(obj)
	if err != nil {
		return 0, err
	}
	return uint(updates.RowsAffected), nil
}

func (receiver *ProjectService) List() ([]*model.Project, error) {
	return query.Project.Find()
}

func (receiver *ProjectService) QueryList(param *dto.ProjectListParam) ([]*model.Project, error) {
	q := query.Project

	if param.Account.Super {
		return q.Preload(q.Environments).Find()
	} else {
		envIds, err := permission.Perm.GetOwnEnvIDs(context.TODO(), param.Account.Username, svc.Environment)
		if err != nil {
			return nil, err
		}
		projectIds, err := permission.Perm.GetOwnProjectIds(context.TODO(), param.Account.Username, svc.Project)
		if err != nil {
			return nil, err
		}
		if len(projectIds) == 0 {
			return []*model.Project{}, nil
		}
		if len(envIds) == 0 {
			return []*model.Project{}, nil
		}

		find, err := q.
			Preload(q.Environments).
			Where(query.Project.ID.In(projectIds...)).
			Find()
		for _, project := range find {
			project.Environments = lo.Filter(project.Environments, func(item model.Environment, index int) bool {
				return gslice.InSlice(envIds, item.ID)
			})
		}
		return find, err

	}
}

func (receiver *ProjectService) Get(project *model.Project) (p *model.Project, err error) {
	if project == nil {
		return nil, errors.New("project is null")
	}
	if project.ID == 0 && project.Name == "" {
		return nil, errors.New("project where missing")
	}
	if project.ID > 0 {
		return query.Project.Where(query.Project.ID.Eq(project.ID)).First()
	}
	if project.Name != "" {
		return query.Project.Where(query.Project.Name.Eq(project.Name)).First()
	}
	return nil, errors.New("project not found")
}

func (receiver *ProjectService) Create(project *model.Project) (uint, error) {
	err := query.Project.Create(project)
	if err != nil {
		return 0, err
	}
	return project.ID, err
}
func (receiver *ProjectService) Delete(project *model.Project) (uint, error) {
	find, err := query.HistoryConfig.Where(query.HistoryConfig.ProjectId.Eq(int(project.ID))).First()
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return 0, err
	}
	if find != nil {
		return 0, errors2.ErrorProjectHasConfig
	}
	deCfg, err := query.DerivedConfig.Where(query.DerivedConfig.ProjectId.Eq(int(project.ID))).First()
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return 0, err
	}
	if deCfg != nil {
		return 0, errors2.ErrorProjectHasConfig
	}
	res, err := query.Project.Where(query.Project.ID.Eq(project.ID)).Delete()
	if err != nil {
		return 0, err
	}
	return uint(res.RowsAffected), nil
}
